package cn.yangliu.nacos.oauth2.web;

import java.util.Objects;
import java.util.Optional;

import cn.yangliu.nacos.comm.enums.GlobalResultCode;
import cn.yangliu.nacos.comm.ex.GlobalException;
import cn.yangliu.nacos.comm.model.Oauth2InsertModel;
import cn.yangliu.nacos.comm.model.Oauth2UpdateOtherModel;
import cn.yangliu.nacos.comm.model.Oauth2UpdateOtherPasswordModel;
import cn.yangliu.nacos.comm.model.Oauth2UpdatePasswordModel;
import cn.yangliu.nacos.comm.model.Oauth2UpdateSelfModel;
import cn.yangliu.nacos.comm.model.Oauth2UserModel;
import cn.yangliu.nacos.comm.model.Oauth2UserQueryModel;
import cn.yangliu.nacos.oauth2.entity.User;
import cn.yangliu.nacos.oauth2.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

/**
 * The interface User controller.
 *
 * @author 问道于盲
 * @date 2019 -04-17
 */
@RestController
@Api(value = "用户操作相关接口", tags = "用户操作相关接口")
@RequestMapping("/user")
public class UserController {

    /**
     * current class instance's member.
     * The User service.
     */
    @Autowired
    private UserService userService;

    /**
     * current class instance's member.
     * The Password encoder.
     */
    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * Open id string.
     *
     * @param authentication the authentication
     * @return the string
     */
    @GetMapping("/openId")
    @ApiOperation("openId")
    public String openId(@ApiIgnore Authentication authentication) {
        User user = (User) authentication.getPrincipal();
        return Objects.requireNonNull(user.getId()).toString();
    }

    /**
     * Principal oauth 2 user model.
     *
     * @param authentication the authentication
     * @return the oauth 2 user model
     */
    @GetMapping("/principal")
    @ApiOperation("获取个人信息")
    public Oauth2UserModel principal(@ApiIgnore Authentication authentication) {
        User principal = (User)authentication.getPrincipal();
        Oauth2UserModel oauth2UserModel = new Oauth2UserModel();
        BeanUtils.copyProperties(principal, oauth2UserModel);
        return oauth2UserModel;
    }

    /**
     * Client info object.
     *
     * @param authentication the authentication
     * @return the object
     */
    @GetMapping("/clientInfo")
    @ApiOperation("clientInfo")
    public Object clientInfo(@ApiIgnore Authentication authentication) {
        return authentication.getPrincipal();
    }

    /**
     * Insert oauth 2 user model.
     *
     * @param model the model
     * @return the oauth 2 user model
     */
    @PostMapping
    @ApiOperation("新增用户")
    public Oauth2UserModel insert(@RequestBody @Validated Oauth2InsertModel model) {
        User user = new User();
        BeanUtils.copyProperties(model, user);

        String password = passwordEncoder.encode(model.getPassword());
        user.setPassword(password);
        return userService.insert(user);
    }


    /**
     * Update self oauth 2 user model.
     *
     * @param model the model
     * @return the oauth 2 user model
     */
    @PutMapping("/updateSelf")
    @ApiOperation("更新自己的基本信息")
    public Oauth2UserModel updateSelf(@RequestBody @Validated Oauth2UpdateSelfModel model) {
        User currentUser = getCurrentUser();
        BeanUtils.copyProperties(model, currentUser);
        return userService.update(currentUser);
    }

    /**
     * Update other oauth 2 user model.
     *
     * @param model the model
     * @return the oauth 2 user model
     */
    @PutMapping("/updateOther")
    @ApiOperation("更新别人的基本信息")
    public Oauth2UserModel updateOther(@RequestBody @Validated Oauth2UpdateOtherModel model) {
        User currentUser = getCurrentUser();
        if (Objects.equals(model.getId(), currentUser.getId())) {
            throw new GlobalException(GlobalResultCode.OPERATE_SELF_FORBIDEN);
        }
        Optional<User> optional = userService.findById(model.getId());
        if (!optional.isPresent()) {
            throw new GlobalException(GlobalResultCode.DATA_NOT_EXIST);
        }
        User user = optional.get();
        BeanUtils.copyProperties(model, user);
        return userService.update(user);
    }

    /**
     * Delete boolean.
     *
     * @param id the id
     * @return the boolean
     */
    @DeleteMapping("/delete/{id}")
    @ApiOperation("删除用户")
    public boolean delete(@PathVariable("id") Long id) {
        User currentUser = getCurrentUser();
        if (Objects.equals(id, currentUser.getId())) {
            throw new GlobalException(GlobalResultCode.OPERATE_SELF_FORBIDEN);
        }
        return userService.deleteUser(id);
    }

    /**
     * Update self password boolean.
     *
     * @param model the model
     * @return the boolean
     */
    @PutMapping("/updateSelfPassword")
    @ApiOperation("修改自己的密码")
    public Boolean updateSelfPassword(@RequestBody @Validated Oauth2UpdatePasswordModel model) {
        User currentUser = getCurrentUser();
        String password = passwordEncoder.encode(model.getPassword());
        return userService.updatePassword(password, currentUser.getId());
    }

    /**
     * Find user oauth 2 user model.
     *
     * @param model the model
     * @return the oauth 2 user model
     */
    @GetMapping("/findOne")
    @ApiOperation("条件查询单个用户")
    public Oauth2UserModel findUser(Oauth2UserQueryModel model) {
        return userService.findUser(model);
    }

    /**
     * Check exist boolean.
     *
     * @param model the model
     * @return the boolean
     */
    @GetMapping("/checkExist")
    @ApiOperation("条件判断用户是否存在")
    public Boolean checkExist(Oauth2UserQueryModel model) {
        return userService.checkExist(model);
    }

    /**
     * Update other password boolean.
     *
     * @param model the model
     * @return the boolean
     */
    @PutMapping("/updateOtherPassword")
    @ApiOperation("修改别人的密码")
    public Boolean updateOtherPassword(@RequestBody @Validated Oauth2UpdateOtherPasswordModel model) {
        String password = passwordEncoder.encode(model.getPassword());
        return userService.updatePassword(password, model.getId());
    }

    /**
     * current class method for getter.
     * Gets current user.
     *
     * @return the current user
     */
    private User getCurrentUser() {
        Authentication authentication =
                SecurityContextHolder.getContext().getAuthentication();
        return (User) authentication.getPrincipal();
    }

}
